package com.oss.service.oss;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.oss.common.BaseResponse;
import com.oss.dto.oss.instrument.AddDto;
import com.oss.dto.oss.instrument.InstrumentListDto;
import com.oss.dto.oss.instrument.PageInstrumentDto;
import com.oss.dto.oss.instrument.UpdateDto;
import com.oss.entity.oss.Instrument;
import com.oss.entity.oss.LastPrice;
import com.oss.enums.IsDeletedEnum;
import com.oss.mapper.oss.InstrumentMapper;
import com.oss.service.system.UserService;
import com.oss.util.SnowFlakeUtil;
import com.oss.vo.oss.instrument.InstrumentLevelVO;
import com.oss.vo.oss.instrument.InstrumentVO;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author chengqiang
 */
@Service
public class InstrumentService extends ServiceImpl<InstrumentMapper, Instrument> {
    @Autowired
    UserService userService;
    @Autowired
    LastPriceService lastPriceService;
    @Autowired
    InstrumentService instrumentService;

    public List<InstrumentVO> selectByList(InstrumentListDto dto){
        LambdaQueryWrapper<Instrument> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(Instrument::getIsDeleted, IsDeletedEnum.NO.getFlag());
        lambdaQueryWrapper.eq(dto.getSubscriptionFlag() != null,Instrument::getSubscriptionFlag,dto.getSubscriptionFlag());
        lambdaQueryWrapper.like(StringUtils.isNotBlank(dto.getCode()),Instrument::getCode,dto.getCode());
        List<Instrument> list = this.list(lambdaQueryWrapper);

        if (CollectionUtils.isEmpty(list)) {
            return new ArrayList<>();
        }
        List<InstrumentVO> tempList = list.stream().map(item->{
            InstrumentVO vo = new InstrumentVO();
            BeanUtils.copyProperties(item,vo);
            vo.setParentId(item.getPid());
            return vo;
        }).collect(Collectors.toList());
        // 模糊查找时 , 直接返回
        if (StringUtils.isNotBlank(dto.getCode()) || dto.getSubscriptionFlag() != null) {
            return tempList;
        }
        Map<String,String> userMap = new HashMap<>();
        // 获取创建人和修改人ID
        Set<String> ids = tempList.stream().map(InstrumentVO::getCreatorId).collect(Collectors.toSet());
        ids.addAll(tempList.stream().map(InstrumentVO::getUpdatorId).collect(Collectors.toSet()));
        userMap = userService.selectByIds(ids);
        Map<String, String> finalUserMap = userMap;
        tempList.stream().forEach(item->{
            item.setCreatorName(finalUserMap.get(item.getCreatorId()));
            item.setUpdatorName(finalUserMap.get(item.getUpdatorId()));
        });
        List<InstrumentVO> firstList = tempList.stream().filter(item->item.getPid().equals("0")).collect(Collectors.toList());
        for (InstrumentVO firstItem : firstList){
            List<InstrumentVO> secondList = tempList.stream().filter(item->item.getPid().equals(firstItem.getId())).collect(Collectors.toList());
            for (InstrumentVO secondItem : secondList){
                List<InstrumentVO> thirdList = tempList.stream().filter(item->item.getPid().equals(secondItem.getId())).collect(Collectors.toList());
                List<InstrumentVO> children = secondItem.getChildrenList();
                if (children == null){
                    children = new ArrayList<>();
                }
                children.addAll(thirdList);
                secondItem.setChildrenList(children);
                secondItem.setChildren(children);
                if (CollectionUtils.isNotEmpty(children)){
                    secondItem.setHasChildren(true);
                }
            }
            List<InstrumentVO> children = firstItem.getChildrenList();
            if (children == null){
                children = new ArrayList<>();
            }
            children.addAll(secondList);
            firstItem.setChildrenList(children);
            firstItem.setChildren(children);
            if (CollectionUtils.isNotEmpty(children)){
                firstItem.setHasChildren(true);
            }
        }
        return firstList;
    }

    /**
     * 删除合约
     * 如果删除的是一级/二级 , 还要删除他的子节点
     * @param id
     * @return
     */
    public String delete(String id) {
        Instrument entity = this.getById(id);
        // 一级
        if (entity.getLevel() == 1) {
            LambdaQueryWrapper<Instrument> wrapper2 = new LambdaQueryWrapper<>();
            wrapper2.eq(Instrument::getIsDeleted, IsDeletedEnum.NO.getFlag());
            wrapper2.eq(Instrument::getPid, id);
            // 二级列表
            List<Instrument> list2 = this.list(wrapper2);
            Set<String> ids = new HashSet<>();
            ids.add(id);
            if (CollectionUtils.isNotEmpty(list2)){
                ids.addAll(list2.stream().map(item->item.getId()).collect(Collectors.toSet()));
                LambdaQueryWrapper<Instrument> wrapper3 = new LambdaQueryWrapper<>();
                wrapper3.eq(Instrument::getIsDeleted, IsDeletedEnum.NO.getFlag());
                wrapper3.in(Instrument::getPid, ids);
                // 三级
                List<Instrument> list3 = this.list(wrapper3);
                if (CollectionUtils.isNotEmpty(list3)){
                    ids.addAll(list3.stream().map(item->item.getId()).collect(Collectors.toSet()));
                }
            }
            // 统一更新
            LambdaUpdateWrapper<Instrument> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.in(Instrument::getId,ids);
            updateWrapper.set(Instrument::getIsDeleted,IsDeletedEnum.YES.getFlag());
            this.update(updateWrapper);
        } else if (entity.getLevel() == 2) {
            LambdaQueryWrapper<Instrument> wrapper2 = new LambdaQueryWrapper<>();
            wrapper2.eq(Instrument::getIsDeleted, IsDeletedEnum.NO.getFlag());
            wrapper2.eq(Instrument::getPid, id);
            // 二级列表
            List<Instrument> list2 = this.list(wrapper2);
            Set<String> ids = new HashSet<>();
            ids.add(id);
            if (CollectionUtils.isNotEmpty(list2)) {
                ids = list2.stream().map(item -> item.getId()).collect(Collectors.toSet());
                ids.addAll(ids);
            }
            // 统一更新
            LambdaUpdateWrapper<Instrument> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.in(Instrument::getId,ids);
            updateWrapper.set(Instrument::getIsDeleted,IsDeletedEnum.YES.getFlag());
            this.update(updateWrapper);

        } else if (entity.getLevel() == 3) {
            LambdaUpdateWrapper<Instrument> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(Instrument::getId,id);
            updateWrapper.set(Instrument::getIsDeleted,IsDeletedEnum.YES.getFlag());
            this.update(updateWrapper);
        }
        return "操作成功";
    }

    public BaseResponse<String> add(AddDto dto) {
        BaseResponse baseResponse = new BaseResponse();
        baseResponse.setCode(1);
        baseResponse.setMessage("操作成功");
        // 添加标的
        if (dto.getLevel() != null && dto.getLevel() != 1) {
            LambdaQueryWrapper<Instrument> lambdaQueryWrapper = new LambdaQueryWrapper<>();
            lambdaQueryWrapper.eq(Instrument::getIsDeleted, IsDeletedEnum.NO.getFlag());
            lambdaQueryWrapper.eq(Instrument::getLevel, dto.getLevel());
            lambdaQueryWrapper.in(Instrument::getCode,dto.getCodeList());
            List<Instrument> list = this.list(lambdaQueryWrapper);
            if (list.size() > 0) {
                String codes = list.stream().map(Instrument::getCode).collect(Collectors.joining(";"));
                baseResponse = BaseResponse.error("合约已存在"+codes);
                return baseResponse;
            } else {
                List<Instrument> unAddList = new ArrayList<>();
                for (String code : dto.getCodeList()) {
                    Instrument entity = new Instrument();
                    BeanUtils.copyProperties(dto,entity);
                    entity.setCode(code);
                    entity.setName(code);
                    entity.setId(SnowFlakeUtil.getID());

                    unAddList.add(entity);
                }
                this.saveBatch(unAddList);
            }
        } else {
            LambdaQueryWrapper<Instrument> lambdaQueryWrapper = new LambdaQueryWrapper<>();
            lambdaQueryWrapper.eq(Instrument::getIsDeleted, IsDeletedEnum.NO.getFlag());
            lambdaQueryWrapper.eq(Instrument::getCode,dto.getCode());
            lambdaQueryWrapper.eq(Instrument::getLevel, dto.getLevel());
            long count = this.baseMapper.selectCount(lambdaQueryWrapper);
            if (count > 0) {
                baseResponse = BaseResponse.error("合约已存在");
                return baseResponse;
            }
            Instrument entity = new Instrument();
            BeanUtils.copyProperties(dto,entity);
            entity.setId(SnowFlakeUtil.getID());
            this.save(entity);
        }
        return baseResponse;
    }

    public String updateData(UpdateDto dto) {
        Instrument entity = new Instrument();
        BeanUtils.copyProperties(dto,entity);
        this.updateById(entity);
        return "操作成功";
    }

    public List<Instrument> getUnExpirationData() {
        LambdaQueryWrapper<Instrument> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(Instrument::getIsDeleted, IsDeletedEnum.NO.getFlag());
        lambdaQueryWrapper.ge(Instrument::getExpirationTime, LocalDateTime.now());
        return this.list(lambdaQueryWrapper);
    }

    /**
     * 根据合约代码获取交易单位
     * 如果合约代码对应二级, 则需要查找他的父级 , 返回对应的交易单位
     * 如果合约代码对应三级, 则需要查找他的二级 , 再找一级 , 返回对应的交易单位
     * @param instrumentCodeSet
     * @return
     */
    public Map<String,Integer> selectVolumeMultipleByInstrumentCodeSet(Set<String> instrumentCodeSet) {
        Map<String,Integer> returnMap = new HashMap<>();
        if (CollectionUtils.isNotEmpty(instrumentCodeSet)){

            LambdaQueryWrapper<Instrument> lambdaQueryWrapper = new LambdaQueryWrapper<>();
            lambdaQueryWrapper.eq(Instrument::getIsDeleted, IsDeletedEnum.NO.getFlag());
            lambdaQueryWrapper.ge(Instrument::getExpirationTime,LocalDateTime.now()); // 过期时间要大于当前日期
            lambdaQueryWrapper.in(Instrument::getCode,instrumentCodeSet);
            List<Instrument> list = this.list(lambdaQueryWrapper);
            if (CollectionUtils.isNotEmpty(list)){
                // 一级的直接返回
                returnMap = list.stream().filter(item->item.getLevel() == 1).collect(Collectors.toMap(Instrument::getCode, item->{
                    return item.getVolumeMultiple() == null ? 0: item.getVolumeMultiple();
                },(v1,v2)->v2));
                // 二级标的
                List<Instrument> secondList = list.stream().filter(item->item.getLevel() == 2).collect(Collectors.toList());
                if (CollectionUtils.isNotEmpty(secondList)){
                    // 二级父ID
                    Set<String> pids = secondList.stream().map(Instrument::getPid).collect(Collectors.toSet());
                    List<Instrument> firstList = this.getBaseMapper().selectBatchIds(pids);
                    // 返回时 , key返回二级code , value=一级交易单位
                    for (Instrument secondItem : secondList) {
                        // 根据父ID筛选父元素 , 父元素只有一个
                        Instrument firstItem = firstList.stream().filter(item->item.getId().equals(secondItem.getPid())).findFirst().orElse(new Instrument());
                        returnMap.put(secondItem.getCode(),firstItem.getVolumeMultiple() == null ? 0 : firstItem.getVolumeMultiple());
                    }
                }
                // 三级期权合约代码
                List<Instrument> thirdList = list.stream().filter(item->item.getLevel() == 3).collect(Collectors.toList());
                if (CollectionUtils.isNotEmpty(thirdList)) {
                    // 三级父ID(二级ID)
                    Set<String> secondIds = thirdList.stream().map(Instrument::getPid).collect(Collectors.toSet());
                    List<Instrument> secondListTemp = this.getBaseMapper().selectBatchIds(secondIds);
                    Set<String> firstIds = secondListTemp.stream().map(Instrument::getPid).collect(Collectors.toSet());
                    List<Instrument> firstList = this.getBaseMapper().selectBatchIds(firstIds);
                    for (Instrument thirdItem : thirdList) {
                        // 根据父ID筛选父元素 , 父元素只有一个
                        Instrument secondInstrument = secondListTemp.stream().filter(item->item.getId().equals(thirdItem.getPid())).findFirst().orElse(new Instrument());
                        Instrument firstItem = firstList.stream().filter(item->item.getId().equals(secondInstrument.getPid())).findFirst().orElse(new Instrument());
                        //key = 三级code , value = 一级的交易单位
                        returnMap.put(thirdItem.getCode(),firstItem.getVolumeMultiple() == null ? 0 : firstItem.getVolumeMultiple());
                    }
                }

            }

            return returnMap;
        } else {
            return returnMap;
        }
    }
    public Map<String,String> selectUnderlyingCodeByInstrumentCodeSet(Set<String> instrumentCodeSet) {
        if (CollectionUtils.isNotEmpty(instrumentCodeSet)){
            LambdaQueryWrapper<Instrument> lambdaQueryWrapper = new LambdaQueryWrapper<>();
            lambdaQueryWrapper.eq(Instrument::getIsDeleted, IsDeletedEnum.NO.getFlag());
            lambdaQueryWrapper.ge(Instrument::getExpirationTime,LocalDateTime.now()); // 过期时间要大于当前日期
            lambdaQueryWrapper.in(Instrument::getCode,instrumentCodeSet);
            List<Instrument> list = this.list(lambdaQueryWrapper);
            return list.stream().collect(Collectors.toMap(Instrument::getCode, item->{
                return item.getCode() == null ? "":item.getCode();
            },(v1,v2)->v2));
        } else {
            return new HashMap<>();
        }
    }

    public Map<String, BigDecimal> selectTradeMarginRateByInstrumentCodeSet(Set<String> instrumentCodeSet) {
        if (CollectionUtils.isNotEmpty(instrumentCodeSet)){
            LambdaQueryWrapper<Instrument> lambdaQueryWrapper = new LambdaQueryWrapper<>();
            lambdaQueryWrapper.eq(Instrument::getIsDeleted, IsDeletedEnum.NO.getFlag());
            lambdaQueryWrapper.ge(Instrument::getExpirationTime,LocalDateTime.now()); // 过期时间要大于当前日期
            lambdaQueryWrapper.in(Instrument::getCode,instrumentCodeSet);
            List<Instrument> list = this.list(lambdaQueryWrapper);
            return list.stream().collect(Collectors.toMap(Instrument::getCode, Instrument::getTradeMarginRate,(v1,v2)->v2));
        } else {
            return new HashMap<>();
        }
    }

    /**
     * 按照合约代码获取交易单位(新增/修改交易)
     * 有可能是标的匹配上, 也有可能是期权合约代码匹配上
     * 若 标的匹配上 , 再向上查询一级即可
     * 若 期权合约代码匹配上 , 再向上查询二级 , 再查询一级即可
     * @param instrumentCode
     * @return
     */
    public BigDecimal getVolumeMultipleByInstrumentCode(String instrumentCode) {
        LambdaQueryWrapper<Instrument> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(Instrument::getIsDeleted, IsDeletedEnum.NO.getFlag());
        lambdaQueryWrapper.ge(Instrument::getExpirationTime,LocalDateTime.now()); // 过期时间要大于当前日期
        lambdaQueryWrapper.eq(Instrument::getCode,instrumentCode);
        Instrument instrument = this.getOne(lambdaQueryWrapper);
        if (instrument== null) {
            return BigDecimal.ZERO;
        } else {
            // 标的代码匹配
            if (instrument.getLevel() == 2) {
                instrument = this.getById(instrument.getPid());
            } else if (instrument.getLevel() == 3) {
                // 期权合约匹配上了
                // 查上一级, 标的
                Instrument instrument2 = this.getById(instrument.getPid());
                // 再查询一级的品种
                instrument = this.getById(instrument2.getPid());
            }
        }
        return instrument.getVolumeMultiple() == null ? BigDecimal.ZERO : new BigDecimal(instrument.getVolumeMultiple());
    }
    /**
     * 按照合约代码获取保证金比率
     * 有可能是标的匹配上, 也有可能是期权合约代码匹配上
     * 若 标的匹配上 , 直接返回
     * 若 期权合约代码匹配上 , 再查询一级即可
     * @param instrumentCode
     * @return
     */
    public BigDecimal getRateByInstrumentCode(String instrumentCode) {
        LambdaQueryWrapper<Instrument> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(Instrument::getIsDeleted, IsDeletedEnum.NO.getFlag());
        lambdaQueryWrapper.ge(Instrument::getExpirationTime,LocalDateTime.now()); // 过期时间要大于当前日期
        lambdaQueryWrapper.eq(Instrument::getCode,instrumentCode);
        List<Instrument> instrumentList = this.list(lambdaQueryWrapper);
        if (CollectionUtils.isEmpty(instrumentList)) {
            return BigDecimal.ZERO;
        }
        Instrument instrument = instrumentList.get(0);
        // 如果是期权合约匹配上
        if (instrument.getLevel() == 3){
            instrument = this.getById(instrument.getPid());
        }
        return instrument.getTradeMarginRate() == null ? BigDecimal.ZERO : instrument.getTradeMarginRate();
    }

    /**
     * 按照合约代码获取最新价代码/(期权合约代码/标的代码)
     * 注意 : 如果合约自身有最新价合约 , 优先使用此合约查询最新价 , 否则使用标的/期权合约代码查询行情最新价
     * @param instrumentCode
     * @return
     */
    public BigDecimal getLastPriceByInstrumentCode(String instrumentCode) {
        LambdaQueryWrapper<Instrument> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(Instrument::getIsDeleted, IsDeletedEnum.NO.getFlag());
        // 过期时间要大于当前日期
        lambdaQueryWrapper.ge(Instrument::getExpirationTime,LocalDateTime.now());
        lambdaQueryWrapper.eq(Instrument::getCode,instrumentCode);
        Instrument instrument = this.getOne(lambdaQueryWrapper);
        if (instrument == null) {
            return BigDecimal.ZERO;
        }
        String code = instrument.getCode();
        // 优先使用合约中自带的行情代码, 如果没有行情代码 , 再使用期权合约/标的合约
        if (StringUtils.isNotBlank(instrument.getLastPriceCode())){
            code = instrument.getLastPriceCode();
        }
        LastPrice lastPrice = lastPriceService.getByUnderlyingCode(code);
        return lastPrice == null ? BigDecimal.ZERO : lastPrice.getLastPrice();
    }

    /**
     * 获取保证金对应的最新价
     * 计算保证经时 , 以交易的合约代码 , 取合约管理中的标的代码 , 再取最新价
     * @param instrumentCode
     * @return
     */
    public BigDecimal getTradeMarginLastPriceByInstrumentCode(String instrumentCode) {
        LambdaQueryWrapper<Instrument> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(Instrument::getIsDeleted, IsDeletedEnum.NO.getFlag());
        // 过期时间要大于当前日期
        lambdaQueryWrapper.ge(Instrument::getExpirationTime,LocalDateTime.now());
        lambdaQueryWrapper.eq(Instrument::getCode,instrumentCode);
        // 正确的数据住有一条
        List<Instrument> instrumentList = this.list(lambdaQueryWrapper);
        if (CollectionUtils.isEmpty(instrumentList)) {
            return BigDecimal.ZERO;
        }
        Instrument instrument = instrumentList.get(0);
        String code = instrument.getCode();
        // 优先使用合约中自带的行情代码, 如果没有行情代码 , 再使用期权合约/标的合约
        if (StringUtils.isNotBlank(instrument.getLastPriceCode()) && instrument.getLevel() == 2){
            code = instrument.getLastPriceCode();
        } else {
            code = this.getById(instrument.getPid()).getLastPriceCode();
        }
        LastPrice lastPrice = lastPriceService.getByUnderlyingCode(code);
        return lastPrice == null ? BigDecimal.ZERO : lastPrice.getLastPrice();
    }

    public IPage<Instrument> selectByPage(PageInstrumentDto dto) {
        LambdaQueryWrapper<Instrument> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(Instrument::getIsDeleted, IsDeletedEnum.NO.getFlag());
        lambdaQueryWrapper.eq(dto.getSubscriptionFlag() != null,Instrument::getSubscriptionFlag, dto.getSubscriptionFlag());
        return this.page(new Page<>(dto.getPageNo(), dto.getPageSize()), lambdaQueryWrapper);
    }

    public InstrumentLevelVO getVOById(String id) {
        InstrumentLevelVO returnVO = new InstrumentLevelVO();
        Instrument entity = this.getById(id);
        // 本次查询的数据是3级
        if (entity.getLevel()==3) {
            returnVO.setVo3(entity);
            Instrument item2 = this.getById(entity.getPid());
            returnVO.setVo2(item2);
            Instrument item1 = this.getById(item2.getPid());
            returnVO.setVo1(item1);
        } else if (entity.getLevel()==2) {
            // 本次查询的数据是2级
            returnVO.setVo2(entity);
            Instrument item1 = this.getById(entity.getPid());
            returnVO.setVo1(item1);
        } else {
            // 本次查询的数据是1级
            returnVO.setVo1(entity);
        }
        return returnVO;
    }

    public List<InstrumentVO> getByPID(String id) {
        List<InstrumentVO> voList = new ArrayList<>();
        LambdaQueryWrapper<Instrument> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(Instrument::getIsDeleted, IsDeletedEnum.NO.getFlag());
        lambdaQueryWrapper.eq(Instrument::getPid,id);
        // 二级/三级数据
        List<Instrument> list = this.list(lambdaQueryWrapper);
        if (CollectionUtils.isNotEmpty(list)) {
            Integer level = list.get(0).getLevel();
            Map<String,List<Instrument>> map = new HashMap<>();
            if (level != null && level == 2){
                // 如果上次查询出来的结果是二级数据 , 还要在查一次三级数据
                List<String> ids = list.stream().map(Instrument::getId).collect(Collectors.toList());
                LambdaQueryWrapper<Instrument> wrapper3 = new LambdaQueryWrapper<>();
                wrapper3.eq(Instrument::getIsDeleted, IsDeletedEnum.NO.getFlag());
                wrapper3.in(Instrument::getPid,ids);
                // 三级数据
                List<Instrument> list3 = this.list(wrapper3);
                map = list3.stream().collect(Collectors.groupingBy(Instrument::getPid));
            }
            // 循环出来的数据 , 同时设置他们是否有子集
            for (Instrument instrument : list) {
                InstrumentVO vo = new InstrumentVO();
                BeanUtils.copyProperties(instrument, vo);
                if (map.containsKey(instrument.getId())) {
                    vo.setHasChildren(true);
                } else {
                    vo.setHasChildren(false);
                }
                voList.add(vo);
            }
        }
        return voList;
    }
}
